#include <cstdio>
#include <iostream>
#include <stdlib.h>
#include <unistd.h>
#include <cstring>
#include <sys/types.h>
#include <sys/wait.h>

#define COMMAND_SIZE 1024
#define FORMAT "%s@%s:%s# "

#define MAXARGC 128
char* g_argv[MAXARGC];
int g_argc;

const char* GetUserName()
{
    const char* name = getenv("USER");
    return name == NULL ? "None" : name;
}

//const char* GetHostName()
//{
//    const char* hostname = getenv("HOSTNAME");
//    return hostname == NULL ? "None" : hostname;
//}

void GetHostName(char* buffer, size_t size)
{
    if (gethostname(buffer, size) != 0)
        strncpy(buffer, "None", size);
}

const char* GetPwd()
{
    const char* pwd = getenv("PWD");
    const char* home = getenv("HOME");
    
    if(!pwd || !home) return "None";
    
    // 替换主目录为\~符号
    if(strncmp(pwd, home, strlen(home)) == 0)
    {
        static char formatted[1024];  // 静态缓冲区
        snprintf(formatted, sizeof(formatted), "~%s", pwd + strlen(home));
        return formatted;
    }
    return pwd;
}

const char* GetHome()
{
    const char* home = getenv("HOME");
    return home;
}

// 制作命令行
void MakeCommandLine(char cmd_prompt[], size_t size)
{
    char hostname[256];
    GetHostName(hostname, sizeof(hostname));
    snprintf(cmd_prompt, size, FORMAT, GetUserName(), hostname, GetPwd());
}

// 打印命令行提示符
void PrintCommandPrompt()
{
    char prompt[COMMAND_SIZE];
    MakeCommandLine(prompt, sizeof(prompt));
    printf("%s", prompt);
    fflush(stdout);
}

// 获取命令行输入
bool GetCommandLine(char* out, size_t size)
{
     // ls -a -l => "ls -a -l\n" 字符串
     char* c = fgets(out, size, stdin);
     if(c == NULL) return false;
     out[strlen(out) - 1] = 0;// 清理\n
     if(strlen(out) == 0) return false;// 如果用户只按下enter
     return true;
}

// 解析命令行
bool CommandParse(char* commandline)
{
    // 命令行分析 "ls -a -l" -> "ls" "-a" "-l"
    g_argc = 0;
    char* token = strtok(commandline, " ");
    while(token)
    {
        g_argv[g_argc++] = token;
        token = strtok(NULL, " ");
    }
    g_argv[g_argc] = token;// NULL也要存入参数表中
    return g_argc > 0 ? true : false;
}

// 打印命令行参数表
void PrintArgv()
{
    for(int i = 0; g_argv[i]; i++)
    {
        printf("argv[%d]->%s\n", i, g_argv[i]);
    }
    printf("argc: %d\n", g_argc);
}

void Cd()
{
    char cwd[1024]; // 用于存储当前工作目录
    if(g_argc == 1) // cd不带参数，直接进入用户主目录
    {
        const char* home = GetHome();
        if (home && chdir(home) == 0)
        {
            if (getcwd(cwd, sizeof(cwd)))
            {
                setenv("PWD", cwd, 1);
            }
        }
    }
    else
    {
        char* where = g_argv[1];
        if (chdir(where) == 0)
        {
            // 关键修复：获取实际的绝对路径
            if (getcwd(cwd, sizeof(cwd)))
            {
                setenv("PWD", cwd, 1);
            }
        }
        else
        {
            perror("cd");
        }
    }
}

// 检测并处理内建命令
bool CheckAndExecBuiltin()
{
    std::string cmd = g_argv[0];
    if(cmd == "cd")
    {
        Cd();
        return true;
    }

    return false;
}

// 执行命令
int Execute()
{
    pid_t id = fork();
    if(id == 0)
    {
        // child
        execvp(g_argv[0], g_argv);
        exit(1);
    }

    // father
    pid_t rid = waitpid(id, NULL, 0);// 阻塞等待指定子进程id，目前不需要获取子进程的退出信息
    (void)rid;// 暂时先不判断返回值
    return 0;
}

int main()
{
    while(1)
    {
        // 1. 打印命令行提示符
        PrintCommandPrompt();

        // 2. 获取用户输入的指令
        char commandline[COMMAND_SIZE];
        if(!GetCommandLine(commandline, sizeof(commandline)))// 获取输入失败，如用户只按下回车键
            continue;    
        
        //printf("echo %s\n", commandline);
        // 3. 解析命令行参数
        if(!CommandParse(commandline))
            continue;
        // PrintArgv();

        // 4. 检测并处理内建命令
        if(CheckAndExecBuiltin())
            continue;

        // 5. 执行命令
        Execute();
    }
    return 0;
}
